package com.qp.opc;

import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

public class OpcUaClientFactory {
    //日志
    private static final Logger logger = LoggerFactory.getLogger(OpcUaClientFactory.class);
    //客户端缓存
    private static Map<String, OpcUaClient> clientConfigMap = new HashMap<>();

    /**
     * 取得客户端
     *
     * @param opc
     * @return
     * @throws Exception
     */
    public static synchronized OpcUaClientFacade getClient(OpcUaConfig opc) throws Exception {
        return getClient(opc, OpcUaClientFactory.class.getSimpleName());
    }

    /**
     * 取得客户端
     *
     * @param opc
     * @param clasz
     * @return
     * @throws Exception
     */
    private static synchronized OpcUaClientFacade getClient(OpcUaConfig opc, String clasz) throws Exception {
        //取得缓存连接
        String serverName = clasz + "#" + opc.getNamespaceIndex() + "#" + opc.getUrl();
        OpcUaClient client = clientConfigMap.get(serverName);
        if (client != null) {
            try {
                //检测可用性
                checkEnable(client);
            } catch (Exception e1) {
                logger.info("第一次缓存取得opc client 检测不通过，休眠{}秒再次检测", sleep(2));
                try {
                    //检测可用性
                    checkEnable(client);
                } catch (Exception ex) {
                    //关闭连接
                    closeClient(client);
                    logger.info("第二次缓存取得opc client 检测不通过，清空缓存，重新申请尝试");
                    client = null;
                    clientConfigMap.remove(serverName);
                }
            }
        }
        //没有可用，则申请
        if (client == null) {
            try {
                //网络无问题，则创建连接
                client = OpcUaUtil.createClient(opc);
                if (client != null) {
                    //缓存连接
                    clientConfigMap.put(serverName, client);
                    logger.info("申请opc client 成功");
                }
            } catch (Exception ex) {
                throw ex;
            }
        }
        return new OpcUaClientFacade().setClient(client).setNamespaceIndex(opc.getNamespaceIndex());
    }


    /**
     * 检测可用性
     *
     * @param client
     * @throws Exception
     */
    private static void checkEnable(OpcUaClient client) throws Exception {
        try {
            client.readNamespaceTable();
//            System.out.println("读取命名空间成功");
        } catch (Exception ex) {
            logger.error("检测客户端异常：" + ex.getMessage(), ex);
            throw ex;
        }
    }

    /**
     * 关闭连接
     *
     * @throws Exception
     */
    private static void closeClient(OpcUaClient client) throws Exception {
        try {
            if (client != null) {
                client.disconnect();
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
    }


    /**
     * 休眠（s）
     *
     * @param retryTimes 重试次数
     * @return
     */
    private static Long sleep(int retryTimes) {
        Long minute = 5L * 60;
        int hour = LocalDateTime.now().getHour();
        try {
            if (hour < 6 || hour > 16) {
                minute = minute * 5;
                Thread.sleep(minute * 1000L);

            } else {
                Thread.sleep(minute * 1000L);
            }
        } catch (Exception ex) {
        }
        return minute;
    }

}
